package br.edu.univas.jobmanager.dao;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import br.edu.univas.jobmanager.exception.ObjectNotFoundException;

public class GenericDAO<Entity, PK> {
	private static final long serialVersionUID = -6834307145880528379L;
	
	@PersistenceContext private EntityManager _entityManager;
	private Class<Entity> _persistentClass = null;
	private boolean _externalTransaction = false;
	
	@SuppressWarnings("unchecked")
	public GenericDAO() {
		_entityManager = ConnectionManager.createEntityManager();
		_persistentClass = (Class<Entity>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	@SuppressWarnings("unchecked")
	public GenericDAO(EntityManager entityManager) {
		_entityManager = entityManager;
		_persistentClass = (Class<Entity>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		_externalTransaction = true;
	}

	public void insert(Entity entity) {
		begin();
		_entityManager.persist(entity);
		end();
	}

	public Entity update(Entity entity) {
		begin();
		Entity result = _entityManager.merge(entity);
		end();

		return result;
	}
	
	public void delete(Entity entity) {
		begin();
		entity = _entityManager.merge(entity);
		_entityManager.remove(entity);
		end();
	}

	
	public Entity refreshEntity(Entity entity) {
		begin();
		Entity result = _entityManager.merge(entity);
		_entityManager.refresh(result);
		end();

		return result;
	}
	
	public Entity findByPK(PK pk) throws ObjectNotFoundException {
		Entity result = null;
		
		result = _entityManager.find(_persistentClass, pk);
		
		if(result == null) {
			throw new ObjectNotFoundException();
		}
			
		return result;	
	}

	@SuppressWarnings("unchecked")
	public ArrayList<Entity> findAll() {
		return new ArrayList<Entity>(_entityManager.createQuery("FROM " + _persistentClass.getName()).getResultList());
	}

	
	
	private void begin() {
		if(!_externalTransaction) {
			_entityManager.getTransaction().begin();
		}
	}

	private void end() {
		if(!_externalTransaction) {
			_entityManager.getTransaction().commit();
		}
	}

	public void flush() {
		begin();
		_entityManager.flush();
		end();
	}
	public EntityManager getEntityManager(){
		return _entityManager;
	}
}

